package com.tbit.uqbike.service.business.impl;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.tbit.common.entity.view.Result;
import com.tbit.uqbike.annos.EncapsulateMap;
import com.tbit.uqbike.constant.enums.AccountDayStatEnum;
import com.tbit.uqbike.enums.SystemCodeEnum;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.pojo.statistics.RideOrderDaySta;
import com.tbit.uqbike.service.base.MachineService;
import com.tbit.uqbike.service.business.AccountService;
import com.tbit.uqbike.service.business.RefundOrderService;
import com.tbit.uqbike.service.business.RideLogService;
import com.tbit.uqbike.webmanager.dao.core.*;
import com.tbit.uqbike.webmanager.dao.log.RideRefundLogDao;
import com.tbit.uqbike.webmanager.dao.stat.AccountDayStatDao;
import com.tbit.uqbike.webmanager.dao.stat.RideOrderDayStaDao;
import com.tbit.uqbike.webmanager.util.StringUtil;
import com.tbit.uqbike.webmanager.util.csv.CsvExportUtils;
import com.tbit.uqbike.webmanager.util.csv.entity.ExportHandler;
import com.tbit.uqbike.webmanager.util.excel.ExcelUtil;
import com.tbit.utils.DateTimeUtil;
import com.tbit.utils.NullUtils;
import lombok.extern.log4j.Log4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.IntSupplier;
import java.util.stream.Collectors;

@Log4j
@Service("rideLogService")
public class RideLogServiceImpl implements RideLogService {
    @Autowired
    CsvExportUtils csvExportUtils;
    @Autowired
    private RideLogDao rideLogDao;
    @Resource
    private UserDao userDao;
    @Resource
    private UserAccountLogDao userAccountLogDao;
    @Resource
    private RideOrderDayStaDao rideOrderDayStaDao;
    @Autowired
    private AccountUserDao accountUserDao;
    @Autowired
    private RideRefundLogDao rideRefundLogDao;
    @Resource
    private AccountDayStatDao accountDayStatDao;
    @Resource
    private MachineService machineService;
    @Resource
    private RefundOrderService refundOrderService;
    @Autowired
    private AccountService accountService;
    @Resource
    private OrderFeeAppealDao orderFeeAppealDao;

    @Override
    public Integer queryCount(List<Integer> userIds, Integer machineId, List<Integer> adAccountIdList, String orderNo) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("userIds", userIds);
        params.put("machineId", machineId);
        params.put("adAccountIdList", adAccountIdList);
        if (StrUtil.isNotEmpty(orderNo)){
            params.put("orderNo", orderNo);
        }
        return rideLogDao.queryCount(params);
    }

    @Override
    public List<RideLog> queryPage(List<Integer> userIds, Integer machineId,
                                   Integer rowCount, Integer pageNO, String sortName, List<Integer> adAccountIdList, String orderNo) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("userIds", userIds);
        params.put("machineId", machineId);
        params.put("start", (pageNO - 1) * rowCount);
        params.put("rowCount", rowCount);
        params.put("sortName", sortName);
        params.put("adAccountIdList", adAccountIdList);
        if (StrUtil.isNotEmpty(orderNo)){
            params.put("orderNo", orderNo);
        }
        List<RideLog> rideLogs = rideLogDao.queryPage(params);
        if (CollectionUtil.isEmpty(rideLogs)){
            return new ArrayList<>();
        }

        Map<String, RideRefundLog> rideRefundLogList = new HashMap<>();
        List<RefundOrder> byBusinessNoList = new ArrayList<>();
        List<String> orderNoList = rideLogs.stream().map(RideLog::getOrderNO).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(orderNoList)){
            rideRefundLogList = rideRefundLogDao.selectLogByOrderNos(orderNoList).stream().collect(Collectors.toMap(RideRefundLog::getOrderNo, rideRefundLog -> rideRefundLog));
            byBusinessNoList = refundOrderService.getByBusinessNoList(orderNoList);
        }

        Map<String, Object> userParam = new HashMap<>();
        userParam.put("userIds", StringUtil.getListString(rideLogs.stream().map(RideLog::getUserId).collect(Collectors.toList())));
        Map<Integer, User> userMap = userDao.getByUserIdBatch(userParam).stream().collect(Collectors.toMap(User::getUserId, user -> user));


        for (RideLog rideLog : rideLogs) {
            //添加手机号
            User user = userMap.get(rideLog.getUserId());
            if (user != null) {
                rideLog.setPhone(user.getPhone());
            }
            //设置退款金额
            RideRefundLog rideRefundLog = rideRefundLogList.get(rideLog.getOrderNO());
            if (!NullUtils.isEmpty(rideRefundLog)) {
                rideLog.setRefundMoney(rideRefundLog.getMoney());
            } else {
                rideLog.setRefundMoney(0);
            }

            if (CollectionUtil.isNotEmpty(byBusinessNoList)) {
                Map<String, List<RefundOrder>> map = byBusinessNoList.stream().collect(Collectors.groupingBy(RefundOrder::getBusinessNO));

                List<RefundOrder> refundOrders1 = map.get(rideLog.getOrderNO());
                if (CollectionUtil.isEmpty(refundOrders1)) {
                    continue;
                }
                // 过滤出退款中状态
                Integer refundStatus = refundOrders1.stream()
                        .filter(order -> {
                            return order.getRefundStatus() == 0 && this.checkRefundTime(order.getRefundTime());//检查退款时间是否在六个小时内
                        })
                        .findFirst()
                        .map(order -> 0)
                        .orElse(null);
                rideLog.setRefundStatus(refundStatus);
            }
        }
        return rideLogs;
    }

    @Override
    public void update(RideLog rideLog) {
        rideLogDao.update(rideLog);
    }

    @Override
    public void updatePayTime(RideLog rideLog) {

        rideLogDao.updatePayTime(rideLog);
    }

    @Override
    public RideLog getByOrderNO(String orderNO) {
        return rideLogDao.getByOrderNO(orderNO);
    }

    @Override
    public List<StatPark> statByPark(Integer accountId, Integer type, Long startTime, Long endTime, Integer pageNO, Integer rowCount, List<Integer> regionIdList, Integer changeType) {
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        map.put("startTime", new Date(startTime));
        map.put("endTime", new Date(endTime));
        if (pageNO != null && rowCount != null) {
            map.put("start", (pageNO - 1) * rowCount);
            map.put("rowCount", rowCount);
        }
        map.put("regionIdList", regionIdList);
        /**查询某个运营区下所有的分区id*/
        List<StatPark> statParks = null;
        /**统计站点借出的订单*/
        if (type == 0 && changeType == 0) {
            statParks = rideLogDao.statByStartPark(map);
            return statParks;
        } else if (type == 1 && changeType == 0) {
            /**统计站点归还的订单*/
            statParks = rideLogDao.statByEndPark(map);
            return statParks;
        } else if (type == 0 && changeType == 1) {
            statParks = rideLogDao.statByStartParkAndRegionId(map);
            for (StatPark statPark : statParks) {
                String RegionName = accountUserDao.getRegionName(statPark.getRegionId());
                statPark.setRegionName(RegionName);
            }
            return statParks;
        } else {
            statParks = rideLogDao.statByEndParkAndRegionId(map);
            for (StatPark statPark : statParks) {
                statPark.setRegionName(accountUserDao.getRegionName(statPark.getRegionId()));
            }
            return statParks;
        }
    }

    @Override
    public Integer statByParkCount(Integer accountId, Integer type, Long startTime, Long endTime, List<Integer> regionIdList, Integer changeType) {
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        map.put("startTime", new Date(startTime));
        map.put("endTime", new Date(endTime));
        map.put("regionIdList", regionIdList);
        if (type == 0 && changeType == 0) {
            return rideLogDao.statByStartParkCount(map);
        } else if (type == 1 && changeType == 0) {
            return rideLogDao.statByEndParkCount(map);
        } else if (type == 0 && changeType == 1) {
            return rideLogDao.statByStartParkCountAndRegionId(map).size();
        } else {
            return rideLogDao.statByEndParkCountAndRegionId(map).size();
        }
    }

    @Override
    public List<StatPark> statRecharge(Integer accountId, Long start, Long end) {
        List<Integer> accountIds = new ArrayList<>();
        accountIds.add(accountId);
        return statByType(accountIds, DateTimeUtil.DateTimeToString(new Date(start)), DateTimeUtil.DateTimeToString(new Date(end)), 0);

    }

    @Override
    public List<StatPark> statLineChart(Integer accountId, Long startTime, Long endTime, String regionIds, Integer type, Boolean sort) {
        List<Integer> accountIds = new ArrayList<>();
        accountIds.add(accountId);
        List<Integer> regionIdsList = StringUtil.getIntegerList(regionIds);
        List<StatPark> statParks = statByTypeByRegionId(accountIds, DateTimeUtil.DateTimeToString(new Date(startTime)), DateTimeUtil.DateTimeToString(new Date(endTime)), type, regionIdsList, sort);
        //查区域 设置当日已投放车辆数和车辆总数
        Map<String,Integer> map = new HashMap<>();
        Map<String,Integer> machineCountMap = new HashMap<>();
        if (0 == type){
            // 获取当日已投放车辆数和车辆总数
            List<AccountDayStat> accountDayStats = accountDayStatDao.selectList(new QueryWrapper<AccountDayStat>()
                    .eq("accountId", accountId)
                    .between("dataDate", parseTime(new Date(startTime)), parseTime(new Date(endTime)))
                    .in("dataType",
                            AccountDayStatEnum.NUMBER_OF_VEHICLES_LAUNCHED.getDataType(),
                            AccountDayStatEnum.TOTAL_NUMBER_OF_VEHICLES.getDataType()));
            /*根据类型筛选*/
            accountDayStats.forEach(accountDayStat -> {
                String dateKey = pareDate(accountDayStat.getDataDate());
                if (accountDayStat.getDataType().equals(AccountDayStatEnum.NUMBER_OF_VEHICLES_LAUNCHED.getDataType())) {
                    map.put(dateKey, (int) accountDayStat.getSumTotal());
                } else if (accountDayStat.getDataType().equals(AccountDayStatEnum.TOTAL_NUMBER_OF_VEHICLES.getDataType())) {
                    machineCountMap.put(dateKey, (int) accountDayStat.getSumTotal());
                }
            });
            //获取当日订单
            statParks.forEach(statPark -> {
                Integer count = map.get(statPark.getName());
                statPark.setMachineNum(Objects.isNull(machineCountMap.get(statPark.getName())) ? 0 : machineCountMap.get(statPark.getName()));
                statPark.setPutInMachineCount(Objects.isNull(count) ? 0 : count);
                statPark.setOrderRate(statPark.getPutInMachineCount() == 0 ? 0.00 :NumberUtil.div(statPark.getHaveOrderCount(), statPark.getPutInMachineCount(), 2).doubleValue());
            });
        }
        return statParks;
    }

    private Integer parseTime(Date time) {
        return Integer.parseInt(DateUtil.format(time, "yyyyMMdd"));
    }

    private String pareDate(Integer time){
        DateTime parse = DateUtil.parse(time.toString(), DatePattern.PURE_DATE_PATTERN);
        return DateUtil.format(parse, "yyyy-MM-dd");
    }


    @Override
    public List<MachineRideLog> getByMachineId(Integer machineId, String phone, String orderNo, Integer rowCount, Integer pageNO) {
        Map<String, Object> map = new HashMap<>();
        map.put("machineId", machineId);
        map.put("phone", phone);
        map.put("orderNO", orderNo);
        map.put("start", (pageNO - 1) * rowCount);
        map.put("rowCount", rowCount);
        List<MachineRideLog> machineRideLogs = rideLogDao.getByMachineId(map);
        List<FeeAppeal> feeAppealList = orderFeeAppealDao.selectList(machineRideLogs.stream().map(MachineRideLog::getOrderNO).collect(Collectors.toList()));
        if (CollectionUtil.isEmpty(feeAppealList)){
            return machineRideLogs;
        }
        Map<String, Integer> appealMap = feeAppealList.stream().collect(Collectors.toMap(FeeAppeal::getOrderNO, FeeAppeal::getAppealId));
        machineRideLogs.forEach(machineRideLog -> machineRideLog.setAppealId(
                appealMap.get(machineRideLog.getOrderNO())
        ));
        return machineRideLogs;
    }

    @Override
    public List<MachineRideLog> getByUserId(Integer userId, String orderNo, List<Integer> accountIdList) {
        List<MachineRideLog> machineRideLogs = rideLogDao.getByUserId(userId, orderNo, accountIdList);
        if (CollectionUtil.isEmpty(machineRideLogs)){
            return machineRideLogs;
        }
        List<FeeAppeal> feeAppealList = orderFeeAppealDao.selectList(machineRideLogs.stream().map(MachineRideLog::getOrderNO).collect(Collectors.toList()));
        if (CollectionUtil.isEmpty(feeAppealList)){
            return machineRideLogs;
        }
        Map<String, Integer> appealMap = feeAppealList.stream().collect(Collectors.toMap(FeeAppeal::getOrderNO, FeeAppeal::getAppealId));
        machineRideLogs.forEach(machineRideLog -> machineRideLog.setAppealId(
                        Objects.isNull(appealMap.get(machineRideLog.getOrderNO())) ? null : appealMap.get(machineRideLog.getOrderNO())
                ));
        return machineRideLogs;
    }

    @Override
    public Integer getByMachineIdCount(Integer machineId, String phone, String orderNo) {
        Map<String, Object> map = new HashMap<>();
        map.put("machineId", machineId);
        map.put("phone", phone);
        map.put("orderNo", orderNo);
        return rideLogDao.getByMachineIdCount(map);
    }

    @Override
    @EncapsulateMap
    public List<RideLog> rechargeQueryPage(HashMap<String, Object> params, Integer accountId, Integer type, Long startTime,
                                           Long endTime, String phone, String userCode, String orderNO, Integer pageNO,
                                           Integer rowCount, Role role, List<Integer> regionList, Integer timeType, Integer ridingTimeMoreThan) {
        params.put("roleId", role.getRoleValue());
        List<RideLog> rechargeQueryPage = rideLogDao.rechargeQueryPage(params);
        if (!NullUtils.isEmpty(rechargeQueryPage)) {
            List<String> orderNumList = new ArrayList<>();
            for (RideLog log : rechargeQueryPage) {
                RideRefundLog rideRefundLog = rideRefundLogDao.selectLog(new RideRefundLog(log.getOrderNO()));
                if (!NullUtils.isEmpty(rideRefundLog)) {
                    log.setRefundMoney(rideRefundLog.getMoney());
                } else {
                    log.setRefundMoney(0);
                }
                orderNumList.add(log.getOrderNO());
            }

            //查询退款状态
            if (CollectionUtil.isNotEmpty(orderNumList)){
                List<RefundOrder> refundOrders = refundOrderService.getByBusinessNoList(orderNumList);
                if (CollectionUtil.isEmpty(refundOrders)){
                    return rechargeQueryPage;
                }
                Map<String, List<RefundOrder>> map = refundOrders.stream().collect(Collectors.groupingBy(RefundOrder::getBusinessNO));
                for (RideLog log : rechargeQueryPage) {
                    List<RefundOrder> refundOrders1 = map.get(log.getOrderNO());
                    if (CollectionUtil.isEmpty(refundOrders1)){
                        continue;
                    }
                    // 过滤出退款中状态
                    Integer refundStatus = refundOrders1.stream()
                            .filter(order -> order.getRefundStatus() == 0)
                            .findFirst()
                            .map(order -> 0)
                            .orElse(null);
                    log.setRefundStatus(refundStatus);
                }
            }
        }
        return rechargeQueryPage;
    }

    @Override
    @EncapsulateMap
    public Integer rechargeQueryCount(HashMap<String, Object> params, Integer accountId, Integer type, Long startTime,
                                      Long endTime, String phone, String userCode, String orderNO, Role role, List<Integer> regionList, Integer timeType, Integer ridingTimeMoreThan) {
        params.put("roleId", role.getRoleValue());
        return rideLogDao.rechargeQueryCount(params);
    }


    @Override
    public List<StatPark> statByType(List<Integer> accountIds, String startTime, String endTime,
                                     Integer type) {
        Date now = new Date();
        long nowTime = now.getTime();
        String ymd = DateTimeUtil.formatDateYMD(now);
        String time = ymd + " 00:00:00";
        long morningStartTime = DateTimeUtil.StringToDateTime(time).getTime();
        time = ymd + " 03:00:00";
        long nightStartTime = DateTimeUtil.StringToDateTime(time).getTime();
        List<StatPark> statParks = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("accountIds", StringUtil.getListString(accountIds));
        map.put("startTime", startTime);
        map.put("endTime", endTime);
        map.put("type", type);
        Map<String, StatPark> stat = new HashMap<>();
        List<String> daysStr = DateTimeUtil.findDaysStr(DateTimeUtil.formatDateYMD(DateTimeUtil.StringToDateTime(startTime)), DateTimeUtil.formatDateYMD(DateTimeUtil.StringToDateTime(endTime)));
        if (type == 0) {
            List<StatPark> statParks1 = rideOrderDayStaDao.statByType(map);
            for (StatPark statPark : statParks1) {
                stat.put(statPark.getName(), statPark);
            }
            daysStr.forEach(day -> {
                Date start = DateTimeUtil.getYesterdayHHMMSS(day, -1);
                Date end = DateTimeUtil.getYesterdayHHMMSS(day, 0);
                map.put("startTime", start);
                map.put("endTime", end);
                if (DateTimeUtil.formatDateYMD(end).equals(DateTimeUtil.getNowTimeYMD()) && rideLogDao.statByType(map).size() > 0) {
                    statParks.add(rideLogDao.statByType(map).get(0));
                } else if (nowTime >= morningStartTime && nowTime < nightStartTime && day.equals(DateTimeUtil.getYesterday()) && rideLogDao.statByType(map).size() > 0) {
                    /**兼容0-3点前一日订单未统计*/
                    statParks.add(rideLogDao.statByType(map).get(0));
                } else {
                    if (stat.containsKey(day)) {
                        statParks.add(stat.get(day));
                    } else {
                        statParks.add(new StatPark(0, 0, day));
                    }
                }
            });
            return statParks;
        }
        return rideLogDao.statByType(map);
    }


    @Override
    public List<StatPark> statByTypeByRegionId(List<Integer> accountIds, String startTime, String endTime,
                                               Integer type, List<Integer> regionIdsList, Boolean sort) {
        Date now = new Date();
        long nowTime = now.getTime();
        String ymd = DateTimeUtil.formatDateYMD(now);
        String time = ymd + " 00:00:00";
        long morningStartTime = DateTimeUtil.StringToDateTime(time).getTime();
        time = ymd + " 03:00:00";
        long nightStartTime = DateTimeUtil.StringToDateTime(time).getTime();
        List<StatPark> statParks = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("accountIds", StringUtil.getListString(accountIds));
        map.put("startTime", startTime);
        map.put("endTime", endTime);
        map.put("type", type);
        map.put("regionIdsList", regionIdsList);
        Map<String, StatPark> stat = new HashMap<>();
        List<String> daysStr = DateTimeUtil.findDaysStr(DateTimeUtil.formatDateYMD(DateTimeUtil.StringToDateTime(startTime)), DateTimeUtil.formatDateYMD(DateTimeUtil.StringToDateTime(endTime)));
        // 定义日期格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        // 使用 Lambda 表达式进行倒序排序
        if (!sort){
            Collections.sort(daysStr, (o1, o2) -> {
                LocalDate date1 = LocalDate.parse(o1, formatter);
                LocalDate date2 = LocalDate.parse(o2, formatter);
                return date2.compareTo(date1); // 倒序
            });
        }
        List<Region> regionList = new ArrayList<>();
        /**查询分区下的数据*/
        if (type == 1) {
            List<StatPark> statParks1 = rideOrderDayStaDao.statByType(map);
            Map<Integer, String> regions = new HashMap<>();
            for (Integer accountId : accountIds) {
                /**查询某个运营区下所有的分区id*/
                regionList = accountUserDao.getRegionId(accountId);
                for (Region region : regionList) {
                    regions.put(region.getRegionId(), region.getRegionName());
                    for (StatPark statPark : statParks1) {
                        if (region.getRegionId().equals(statPark.getRegionId())) {
                            statPark.setRegionName(region.getRegionName());
                        }
                    }
                }
            }
            if (regionIdsList.size() > 0) {
                regionList.clear();
                for (Integer integer : regionIdsList) {
                    regionList.add(new Region(regions.get(integer), integer));
                }
            }

            Map<Integer, Region> regionMap = new HashMap<>(regionList.size());
            for (Region region : regionList) {
                regionMap.put(region.getRegionId(), region);
            }

            for (StatPark statPark : statParks1) {
                stat.put(statPark.getName() + "_" + statPark.getRegionId(), statPark);
            }

            for (Region region : regionList) {
                daysStr.forEach(day -> {
                    Date start = DateTimeUtil.getYesterdayHHMMSS(day, -1);
                    Date end = DateTimeUtil.getYesterdayHHMMSS(day, 0);
                    map.put("startTime", start);
                    map.put("endTime", end);
                    map.put("region", region.getRegionId());
                    /**用户查询今天订单*/
                    String regionName = region.getRegionName();
                    if (DateTimeUtil.formatDateYMD(end).equals(DateTimeUtil.getNowTimeYMD()) && rideLogDao.statByType(map).size() > 0) {
                        List<StatPark> statParkList = rideLogDao.statByType(map);
                        for (StatPark statPark : statParkList) {
                            if (statPark.getRegionId().equals(region.getRegionId())) {
                                statParks.add(new StatPark(rideLogDao.statByType(map).get(0).getTotal(), rideLogDao.statByType(map).get(0).getMoney(), day, region.getRegionId(), regionName));
                            } else {
                                statParks.add(new StatPark(0, 0, day, region.getRegionId(), regionName));
                            }
                        }
                        /**查询昨天订单，并且查询的时间在今天的0点到3点内*/
                    } else if (nowTime >= morningStartTime && nowTime < nightStartTime && day.equals(DateTimeUtil.getYesterday()) && rideLogDao.statByType(map).size() > 0) {
                        /**兼容0-3点前一日订单未统计*/
                        List<StatPark> statParkList = rideLogDao.statByType(map);
                        for (StatPark statPark : statParkList) {
                            if (statPark.getRegionId().equals(region.getRegionId())) {
                                statParks.add(rideLogDao.statByType(map).get(0));
                            } else {
                                statParks.add(new StatPark(0, 0, day, region.getRegionId(), regionName));
                            }
                        }
                    } else {
                        if (stat.containsKey(day + "_" + region.getRegionId())) {
                            statParks.add(stat.get(day + "_" + region.getRegionId()));
                        } else {
                            statParks.add(new StatPark(0, 0, day, region.getRegionId(), regionName));
                        }
                    }
                });
            }

            //查询分区的每天车辆数
            List<Integer> regionIds = statParks.stream().map(StatPark::getRegionId).collect(Collectors.toList());
            List<String> names = statParks.stream().map(StatPark::getName).collect(Collectors.toList());
            Map<String, Map> machineCountMap = new HashMap<>();
            if (regionIds.size() > 0 && names.size() > 0) {
                machineCountMap = rideOrderDayStaDao.getMachineNumRegionByDay(regionIds, names);
            }
            //获取分区每日包含订单车辆数
            Map<String, Map<String,Object>> hasOrderMap = rideLogDao.getHasOrder(startTime, endTime, accountIds, regionIds, type);
            for (StatPark statPark : statParks) {
                Integer countMachine = machineCountMap.get(statPark.getName() + "_" + statPark.getRegionId()) == null ? 0 : Integer.parseInt(machineCountMap.get(statPark.getName() + "_" + statPark.getRegionId()).get("countMachine").toString());
                statPark.setMachineNum(countMachine);
                Integer hasOrderCount = hasOrderMap.get(statPark.getName() + "_" + statPark.getRegionId()) == null ? 0 : Integer.parseInt(hasOrderMap.get(statPark.getName() + "_" + statPark.getRegionId()).get("hasOrderCount").toString());
                statPark.setHaveOrderCount(hasOrderCount);
            }
            return statParks;
            /**查询运营下的数据，没有选择分区*/
        } else if (type == 0) {
            List<StatPark> statParks1;
            if (CollectionUtil.isNotEmpty(regionIdsList)) {
                statParks1 = rideOrderDayStaDao.statRegion(map);
            } else {
                statParks1 = rideOrderDayStaDao.statByType(map);
            }
            for (StatPark statPark : statParks1) {
                stat.put(statPark.getName(), statPark);
            }
            List<StatPark> machineNumList = new LinkedList<>();
            daysStr.forEach(day -> {
                Date start = DateTimeUtil.getYesterdayHHMMSS(day, -1);
                Date end = DateTimeUtil.getYesterdayHHMMSS(day, 0);
                map.put("startTime", start);
                map.put("endTime", end);
                if (DateTimeUtil.formatDateYMD(end).equals(DateTimeUtil.getNowTimeYMD()) && rideLogDao.statByType(map).size() > 0) {
                    statParks.add(rideLogDao.statByAccount(map).get(0));
                } else if (nowTime >= morningStartTime && nowTime < nightStartTime && day.equals(DateTimeUtil.getYesterday()) && rideLogDao.statByType(map).size() > 0) {
                    /**兼容0-3点前一日订单未统计*/
                    statParks.add(rideLogDao.statByAccount(map).get(0));
                } else {
                    if (stat.containsKey(day)) {
                        statParks.add(stat.get(day));
                    } else {
                        statParks.add(new StatPark(0, 0, day));
                    }
                }
                /**查询每天的车辆数*/
                Map<String, Object> findMap = new HashMap<>();
                findMap.put("day", day);
                findMap.put("accountIds", StringUtil.getListString(accountIds));
                StatPark statPark = rideOrderDayStaDao.getMachineNumByDay(findMap);
                if (null == statPark) {
                    statPark = new StatPark(day, 0);
                }
                machineNumList.add(statPark);
            });
            /**取出集合中的null*/
//            machineNumList.removeAll(Collections.singleton(null));
            Map<String, Object> objectMap = new HashMap<>();
            if (!machineNumList.isEmpty()) {
                for (StatPark statPark : machineNumList) {
                    objectMap.put(statPark.getName(), statPark.getMachineNum());
                }
            }
            //获取分区每日包含订单车辆数
            Map<String, Map<String,Object>> hasOrderMap = rideLogDao.getHasOrder(startTime, endTime, accountIds, null, type);
            for (StatPark statPark : statParks) {
                if (objectMap.get(statPark.getName()) != null) {
                    statPark.setMachineNum((Integer) objectMap.get(statPark.getName()));
                }
                Integer hasOrderCount = hasOrderMap.get(statPark.getName()) == null ? 0 : Integer.parseInt(hasOrderMap.get(statPark.getName()).get("hasOrderCount").toString());
                statPark.setHaveOrderCount(hasOrderCount);
            }
            return statParks;
        }
        return rideLogDao.statByType(map);
    }


    @Override
    public MoneyData statMoney(Integer accountId, Integer orderPayType, Integer timeType, Long startTime, Long endTime) {
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        if (startTime != null) {
            map.put("startTime", new Date(startTime));
        }
        if (endTime != null) {
            map.put("endTime", new Date(endTime));
        }
        map.put("orderPayType", orderPayType);
        map.put("timeType", timeType);
        return rideLogDao.statMoneyByPayType(map);
    }

    @Override
    public List<RideLog> userPage(Integer accountId, Integer orderPayType, Integer timeType, Long startTime, Long endTime, Integer pageNO,
                                  Integer rowCount) {
        Map<String, Object> map = new HashMap<>();
        if (startTime != null) {
            map.put("startTime", new Date(startTime));
        }
        map.put("accountId", accountId);
        if (endTime != null) {
            map.put("endTime", new Date(endTime));
        }
        map.put("start", (pageNO - 1) * rowCount);
        map.put("rowCount", rowCount);
        map.put("orderPayType", orderPayType);
        map.put("timeType", timeType);
        List<RideLog> logs = rideLogDao.userPage(map);
        return logs;
    }

    @Override
    public Integer userCount(Integer accountId, Integer orderPayType, Integer timeType, Long startTime, Long endTime) {
        Map<String, Object> map = new HashMap<>();
        if (startTime != null) {
            map.put("startTime", new Date(startTime));
        }
        map.put("accountId", accountId);
        if (endTime != null) {
            map.put("endTime", new Date(endTime));
        }
        map.put("orderPayType", orderPayType);
        map.put("timeType", timeType);
        return rideLogDao.userCount(map);
    }

    @Override
    public List<RideLog> userExport(Integer accountId, Integer orderPayType, Integer timeType, Long startTime, Long endTime) {
        Map<String, Object> map = new HashMap<>();
        if (startTime != null) {
            map.put("startTime", new Date(startTime));
        }
        map.put("accountId", accountId);
        if (endTime != null) {
            map.put("endTime", new Date(endTime));
        }
        map.put("orderPayType", orderPayType);
        map.put("timeType", timeType);
        Integer count = rideLogDao.userCount(map);
        if (count > 65535) {
            throw new BaseException("导出数据量过大，请调整查询条件");
        }
        return rideLogDao.userExport(map);
    }

    @Override
    public List<Map<String, Object>> getRideRank(RideLog rideLog) {
        if (!NullUtils.isEmpty(rideLog.getPage())) {
            PageHelper.startPage(rideLog.getPage().getPageNO(), rideLog.getPage().getRowCount());
        }
        return rideLogDao.selectRideRank(rideLog);
    }

    @Override
    //@Transactional(rollbackFor = Exception.class)
    public void updateRidelog(RideLog rideLog) {
        RideLog rides = rideLogDao.getByOrderNO(rideLog.getOrderNO());

        if (null == rides || !rideLog.getUserCode().equals(rides.getUserCode()) || null != rides.getPayTime()) {
            throw new BaseException(SystemCodeEnum.ORDER_DOES_TO_EXIST);
        }

        if (rideLog.getMoney() > rides.getMoney()) {
            throw new BaseException("修改的金额不能大于订单的金额");
        }
        //修改的金额
        Integer money = rideLog.getMoney();
        //更新用户信息
        Integer rideMoney;
        User user = userDao.getByUserId(rides.getUserId());

        /*if (money == 0) {
            rideMoney = 0;
            money = 0;
        } else {
            if (user.getMoney() > money) {
                rideMoney = 0;
                money = user.getMoney() - money;
                rideLog.setPaytime(new Date());
            } else {
                rideMoney = money;
                money = 0;
            }
        }*/

        //需要在用户余额扣款的金额
        Integer subMoney;
        //用户金额
        Integer userMoney = user.getMoney();
        if (userMoney >= money) {
            //用户余额足以支付，直接扣，欠款清0
            subMoney = money;
            rideMoney = 0;
        } else {
            //不足以支付，用户金额不用扣，剩下的为欠款
            subMoney = 0;
            //欠款 = 修改后的订单金额
            rideMoney = money;
        }


        Map<String, Object> params = new HashMap<>();
        //params.put("money", -money);
        params.put("money", -subMoney);
        params.put("rideMoney", rideMoney);
        params.put("userId", rides.getUserId());
        params.put("updateTime", new Date());
        userDao.updateMoney(params);
        //更新用户骑行订单

        rideLog.setUserMoney(rideMoney);
        rideLogDao.updateRidelog(rideLog);
        /**
         * 更新用户账单
         * */
        rides.setPaytime(new Date(rides.getEndTime().getTime() + 10 * 1000L));
        //流水的入库有可能比订单结束时间还早，需要兼容
        rides.setEndtime(new Date(rides.getEndTime().getTime() - 5 * 1000L));
        UserAccountLog userAccountLog = userAccountLogDao.getByUserAccountLog(rides);
        if (null == userAccountLog) {
            throw new BaseException(SystemCodeEnum.RIDELOG_UPDATE_FALSE);
        }
        userAccountLog.setNewMoney(rideLog.getMoney());
        userAccountLog.setRemark(rideLog.getRemark());
        userAccountLogDao.updateMoney(userAccountLog);
    }


    @Override
    public List<Map<String, Object>> ridelogByDay(Integer accountId, Long startTime, Long endTime, List<Integer> list) {
        List<Map<String, Object>> results = new ArrayList<>();
        Map<String, Object> params = new HashMap<>();
        params.put("accountId", accountId);
        params.put("startTime", new Date(startTime));
        params.put("endTime", new Date(endTime));
        params.put("regionList", list);
        Date now = new Date();
        long nowTime = now.getTime();
        String ymd = DateTimeUtil.formatDateYMD(now);
        String time = ymd + " 00:00:00";
        long morningStartTime = DateTimeUtil.StringToDateTime(time).getTime();
        time = ymd + " 03:00:00";
        long nightStartTime = DateTimeUtil.StringToDateTime(time).getTime();
        Map<String, RideOrderDaySta> stat = new HashMap<>();
        List<String> daysStr = DateTimeUtil.findDaysStr(DateTimeUtil.formatDateYMD(new Date(startTime)), DateTimeUtil.formatDateYMD(new Date(endTime)));
        List<RideOrderDaySta> rideOrderDayStas = rideOrderDayStaDao.queryByMapByRegion(params);
        for (RideOrderDaySta rideOrderDaySta : rideOrderDayStas) {
            stat.put(DateTimeUtil.formatDateYMD(rideOrderDaySta.getOrderDate()), rideOrderDaySta);
        }
        daysStr.stream().forEach(day -> {
            Map<String, Object> result = new HashMap<>();
            Date start = DateTimeUtil.getYesterdayHHMMSS(day, -1);
            Date end = DateTimeUtil.getYesterdayHHMMSS(day, 0);
            params.put("startTime", start);
            params.put("endTime", end);
            long money;
            int num;
            if (day.equals(DateTimeUtil.formatDateYMD(new Date()))) {
                MoneyData moneyData = rideLogDao.statMoneyByRegion(params);
                money = moneyData.getMoney();
                num = moneyData.getNum();
            } else if (nowTime >= morningStartTime && nowTime < nightStartTime && day.equals(DateTimeUtil.getYesterday())) {
                /**兼容0-3点前一日订单未统计*/
                MoneyData moneyData = rideLogDao.statMoneyByRegion(params);
                money = moneyData.getMoney();
                num = moneyData.getNum();
            } else {
                if (stat.containsKey(day)) {
                    money = stat.get(day).getOrderMoney();
                    num = stat.get(day).getOrderCount();
                } else {
                    money = 0;
                    num = 0;
                }
            }
            result.put("money", money);
            result.put("num", num);
            result.put("time", day);
            results.add(result);
        });
        return results;
    }

    @Override
    public List<Map<String, Object>> arrearsStatistics(RideLog rideLog, boolean b) {
        if (b) {
            PageHelper.startPage(rideLog.getPage().getPageNO(), rideLog.getPage().getRowCount());
        }
        return rideLogDao.arrearsStatistics(rideLog);
    }

    @Override
    @EncapsulateMap
    public List<Map<String, Object>> statOrderByPark(HashMap<String, Object> params, Integer accountId, String name, String orderNO, Integer userCode, String phone, Integer type, Long startTime, Long endTime) {
        return rideLogDao.statOrderByPark(params);
    }


    @Override
    public String rideLogCsvExportCsv(Integer accountId, Integer type, Long startTime, Long endTime, String phone, String userCode, String orderNO, Role role, List<Integer> regionList, Integer timeType, Integer ridingTimeMoreThan) {
        File tempFile = csvExportUtils.getTempFile();
        try {
            Map<String, Object> queryMap = new HashMap<>(16);
            queryMap.put("accountId", accountId);
            queryMap.put("type", type);
            queryMap.put("startTime", new Date(startTime));
            queryMap.put("endTime", new Date(endTime));
            queryMap.put("phone", phone);
            queryMap.put("userCode", userCode);
            queryMap.put("orderNO", orderNO);
            queryMap.put("roleId", role.getRoleValue());
            queryMap.put("regionList", regionList);
            queryMap.put("timeType", timeType);
            queryMap.put("ridingTimeMoreThan", ridingTimeMoreThan);
            //查询总条数
            IntSupplier countFn = () -> rideLogDao.rechargeQueryCount(queryMap);

            //单次查询数据
            ExportHandler<RideLog> exportHandler = baseEntity -> {
                Date sTime = baseEntity.getStartTime() == null ? null : baseEntity.getStartTime();
                Date eTime = baseEntity.getEndTime() == null ? null : baseEntity.getEndTime();
                //多线程下使用外部map会有并发问题
                Map<String, Object> queryMap2 = new HashMap<>(16);
                queryMap2.put("accountId", accountId);
                queryMap2.put("type", type);
                queryMap2.put("startTime", sTime);
                queryMap2.put("endTime", eTime);
                queryMap2.put("phone", phone);
                queryMap2.put("userCode", userCode);
                queryMap2.put("orderNO", orderNO);
                queryMap2.put("roleId", role.getRoleValue());
                queryMap2.put("regionList", regionList);
                queryMap2.put("timeType", timeType);
                queryMap2.put("ridingTimeMoreThan", ridingTimeMoreThan);
                List<RideLog> rideLogs = rideLogDao.rechargeQueryExport(queryMap2);
                for (RideLog rideLog : rideLogs) {
                    if (Objects.isNull(rideLog.getMoney())){
                        rideLog.setMoney(0);
                    }
                    rideLog.setMoneyYuan(NumberUtil.div(rideLog.getMoney().intValue(), 100, 2));
                }
                return rideLogs;
            };
            File file = csvExportUtils.exportBigCsvUseDynamicDate(exportHandler, RideLog.class, countFn,
                    new Date(startTime), new Date(endTime), tempFile, "订单记录详细导出");
            String uploadFileName = UUID.randomUUID().toString().replace("-", "");
            return csvExportUtils.uploadZip(tempFile, uploadFileName, file);
        } finally {
            FileUtil.del(tempFile);
        }
    }

    @Override
    public List<RideLog> getRecentUser(Integer machineId, Integer accountId, Integer pageNO, Integer rowCount) {
        List<RideLog> rideLogList;
        /* 设备是否存在判断*/
        Machine machine = machineService.getByMachineId(machineId);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        pageNO = pageNO - 1;
        rideLogList = rideLogDao.getRecentUserByUserCode(machineId,accountId,pageNO,rowCount);
        return rideLogList;
    }

    @Override
    public Result<Object> rideLogCsvExport(Integer accountId, Integer type, Long startTime, Long endTime, String phone, String userCode, String orderNO, Role role, List<Integer> regionList, Integer timeType, Integer ridingTimeMoreThan) {
        Map<String, Object> queryMap2 = new HashMap<>(16);
        queryMap2.put("accountId", accountId);
        queryMap2.put("type", type);
        queryMap2.put("startTime", new Date(startTime));
        queryMap2.put("endTime", new Date(endTime));
        queryMap2.put("phone", phone);
        queryMap2.put("userCode", userCode);
        queryMap2.put("orderNO", orderNO);
        queryMap2.put("roleId", role.getRoleValue());
        queryMap2.put("regionList", regionList);
        queryMap2.put("timeType", timeType);
        queryMap2.put("ridingTimeMoreThan", ridingTimeMoreThan);
        List<RideLog> rideLogs = rideLogDao.rechargeQueryExport(queryMap2);
        ExcelUtil<RideLog> excelUtil = new ExcelUtil(RideLog.class);
        String fileName = String.format("%s~%s_订单详细记录导出", DateUtil.formatDate(new Date(startTime)), DateUtil.formatDate(new Date(endTime)));
        return Result.success(excelUtil.exportExcel(rideLogs, fileName).getData());
    }

    @Override
    public Account getAccountByUserOrder(Integer userId, List<Integer> accountIdList) {
        RideLog rideLog = rideLogDao.getLastByUserIdAndAccountId(userId, accountIdList);
        if (rideLog == null){
            for (Integer accountId : accountIdList) {
                Account account = accountService.getById(accountId);
                if (account.getDelFlag() == 0){
                    return account;
                }
            }
        }
        return accountService.getById(rideLog.getAccountId());
    }

    /**
     * @description: 检查退款时间是否在六个小时内
     * @author: mo.shanyong
     * @date: 2025/5/8 17:02
     * @param: refundTime 退款时间
     * @return: boolean
     */
    private boolean checkRefundTime(String refundTime){
        if (StringUtils.isBlank(refundTime)){
            return false;
        }
        LocalDateTime refundDateTime = DateTimeUtil.getLocalDateTimeByTimeStr(refundTime);
        long between = ChronoUnit.MINUTES.between(refundDateTime, LocalDateTime.now());
        //退款时间距离现在必须是6个小时内的,误差一分钟内
        return between <= (6 * 60);
    }
}